﻿package com.shuqi.model.parse.parser;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import nl.siegmann.epublib.domain.Book;
import nl.siegmann.epublib.domain.SpineReference;
import nl.siegmann.epublib.domain.TOCReference;
import nl.siegmann.epublib.epub.EpubReader;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import android.app.Activity;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import com.shuqi.common.utils.Log4an;
import com.shuqi.common.utils.StringUtils;
import com.shuqi.common.utils.ToastUtil;
import com.shuqi.common.utils.Util;
import com.shuqi.interfaces.OnAfterLoadPage;
import com.shuqi.model.bean.BookContentInfo;
import com.shuqi.model.parse.BookContentParserBase;

/**
 * 解析EPUB文件app
 * 
 * @author Jianda.Yang
 * 
 * @Date 2014-2-7 下午4:59:20
 */
public class BookContentLocalAppEPUBParser extends BookContentParserBase {

    private static final String TAG = "BookContentLocalAppEPUBParser";

    /** 当前书籍信息 */
    private BookContentInfo currBookInfos;
    /** 当前个包的目录 */
    public List<BookContentInfo> currCatalogList;
    private int cur_chapterindex;
    /** 上一章缓存 */
    private BookContentInfo prevInfo;
    /** 当前章缓存 */
    private BookContentInfo currInfo;
    /** 下一章缓存 */
    private BookContentInfo nextInfo;
    /** 当前章文件名 */
    private String currFileName;
    /** 百分比的格式 */
    private DecimalFormat formater = new DecimalFormat("#0.##");

    /** TODO epublib */
    private Book book;
    private List<SpineReference> spineList;
    private List<BookContentInfo> list = new ArrayList<BookContentInfo>();;
    private List<TOCReference> reference;


    /** 根据进度获取章节名 */
    public BookContentInfo getCurCharpterNameFromProgress(Context context, BookContentInfo params) {
        BookContentInfo info = params;

        currFileName = params.getFliePath();
        if (TextUtils.isEmpty(currFileName) || !new File(currFileName).exists()) {
            params.setErrorMessage("文件已删除");
            return null;
        }

        initParams(params);
        initCataLogList();

        if (currCatalogList != null && currCatalogList.size() > cur_chapterindex) {
            info.setCurChapterName(currCatalogList.get(cur_chapterindex).getCurChapterName());
        }

        return info;
    }

    @Override
    public BookContentInfo getCurInfos(Context context, BookContentInfo params, boolean isNext,
            OnOneChpaterLoadDone callBack) {
        currFileName = params.getFliePath();
        if (TextUtils.isEmpty(currFileName) || !new File(currFileName).exists()) {
            params.setErrorMessage("文件已删除");
            return null;
        }

        initParams(params);
        initCataLogList();
        currInfo = getInfo(params, cur_chapterindex);
        resetCurInfoBookName();
        return currInfo;
    }

    private void initParams(BookContentInfo params) {
        // params = new String[]{"/sdcard/斗破苍穹.epub",null};
        currFileName = params.getFliePath();
        Log.d(TAG, "getCurInfos currFileName：" + currFileName);
        try {
            if (params.getCurChapterCid() != null) {
                cur_chapterindex = Integer.valueOf(params.getCurChapterCid());
            }

            Log.d(TAG, "getCurInfos cur_chapterindex : " + cur_chapterindex);
        } catch (NumberFormatException e1) {
            e1.printStackTrace();
        }
        Log.d(TAG, "getCurInfos currCatalogList is null : " + (currCatalogList == null));
    }

    private void resetCurInfoBookName() {
        if (currInfo != null) {
            currInfo.setEncoding("UTF-8");
            currInfo.setBookname(currBookInfos == null ? "" : currBookInfos.getBookname());
        }
    }

    private void initCataLogList() {
        // 获取当前包目录和书籍信息
        if (currCatalogList == null) {

            InputStream is = null;

            try {
                String cataLogListContent = getFileContentFromZip(currFileName, ".ncx");
                if (StringUtils.isEmpty(cataLogListContent)) {
                    cataLogListContent = "";
                }
                ByteArrayInputStream bin = new ByteArrayInputStream(cataLogListContent.getBytes());
                // 解析获取文件信息
                currBookInfos = new BookContentInfo();
                // TODO
//                is = new FileInputStream(currFileName);
//                if (is != null) {
//                    book = new EpubReader().readEpub(is);
//                    is.close();
//                }
                book = new EpubReader().readEpubLazy(currFileName,"UTF-8");
                Log4an.i("youyang", "书籍名称getFirstTitle：" + book.getMetadata().getFirstTitle());
                Log4an.i("youyang", "书籍名称getTitle：" + book.getTitle());
                if (StringUtils.isNotEmpty(book.getTitle())) {
                    currBookInfos.setBookname(book.getTitle());
                }

                // currBookInfos.setBookname(book.getTitle());
                spineList = book.getSpine().getSpineReferences();
                reference = book.getTableOfContents().getTocReferences();
                EpubBookListHandler handler = new EpubBookListHandler(currBookInfos);
                XMLHelper.doInputSteamParse(handler, bin);
                // 解析获取章节信息
                // 获取目录
                currCatalogList = handler.getParserData();
            } catch (Throwable e) {
                e.printStackTrace();
                ToastUtil.showMessage("文件过大，解析内容失败");
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                    }
                }
            }
        }
    }

    public BookContentInfo getInfo(BookContentInfo params, int chapterIndex) {

        // Log.d(TAG, "getInfo chapterIndex : " + chapterIndex);

        BookContentInfo info = params;

        if (info == null)
            info = new BookContentInfo();

        try {
            if (currCatalogList != null && currCatalogList.size() > chapterIndex) {

                final String chapterPath = currCatalogList.get(chapterIndex).getChapterpath();

                // Log.d(TAG, "getInfo chapterPath : " + chapterPath);

                String contentString = getFileContentFromZip(currFileName, chapterPath);

                if (contentString != null) {

                    /* 查找图片数量并跳过图片 */
                    int start = 0;
                    int end = 0;
                    int imageNumber = 0;
                    while ((start = contentString.indexOf("<img", end)) != -1) {
                        end = contentString.indexOf("/>", start);
                        imageNumber++;
                    }
                    StringBuffer imageString = new StringBuffer();
                    /* 图片之换成文字"《图》" */
                    for (int i = 0; i < imageNumber; i++) {
                        imageString.append("《图》" + "\n");
                    }

                    /* 获取内容区域 */
                    if (contentString.indexOf("<body>") != -1) {
                        contentString =
                                contentString.substring(contentString.indexOf("<body>") + 6,
                                        contentString.lastIndexOf("</body>"));
                    }

                    Document doc = Jsoup.parseBodyFragment(contentString);
                    Element body = doc.body();
                    final String prseBody = body.text();
                    contentString = prseBody == null ? contentString : prseBody;

                    if (imageString.length() > 0) {
                        contentString = imageString.toString() + contentString;
                    }

                    contentString =
                            contentString.replaceAll(
                                    "<[/]?[A-Za-z0-9 ]+[=]?['\"]?[A-Za-z0-9. ]+['\"]?[/]?>", "");
                    contentString = contentString.replaceAll("<[/]?[A-Za-z0-9 ]+[/]?>", "　　");
                } else {
                    contentString = "文件缺失";
                }
                info.setCurChapterName(currCatalogList.get(chapterIndex).getCurChapterName());
                final byte[] bytes = contentString.getBytes();
                info.setCurChapterBytes(bytes);
                info.setTotalLength(currCatalogList.size());
                info.setCurChapterCid(cur_chapterindex + "");
                info.setNextChapterCid(String.valueOf(Math.min(currCatalogList.size(),
                        chapterIndex + 1)));
                info.setPreChapterCid(String.valueOf(Math.max(0, chapterIndex - 1)));
                try {
                    Log4an.e("epub", "currCatalogList.size()=" + currCatalogList.size());
                    info.setPercent1(String.valueOf(formater.format((chapterIndex + 1) * 100f
                            / currCatalogList.size())));
                    Log4an.e("epub", "getPercent1=" + info.getPercent1());
                } catch (Exception e) {
                    info.setPercent1("0");
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return info;
    }


    /**
     * 从文件中解压出指定文件
     * 
     * @param fileName 文件名
     * @return
     */
    public static String getFileContentFromZip(String path, String fileName) {
        InputStream is = null;
        String contentString = null;
        try {
            ZipFile zipFile = new ZipFile(path);
            Enumeration<? extends ZipEntry> entrys = zipFile.entries();
            while (entrys.hasMoreElements()) {
                ZipEntry zipEntry = entrys.nextElement();
                if (zipEntry != null && zipEntry.getName().endsWith(fileName)) {
                    is = zipFile.getInputStream(zipEntry);
                    break;
                }
            }

            if (is != null) {
                InputStreamReader isr = new InputStreamReader(is, "UTF-8");
                /* 读取字符串 */
                char[] content = new char[1024];
                StringBuffer sb = new StringBuffer();
                int length;
                while (true) {
                    length = isr.read(content);
                    if (length == -1) {
                        break;
                    } else if (length < 1024) {
                        sb.append(new String(content).substring(0, length));
                    } else {
                        sb.append(new String(content));
                    }
                }
                contentString = sb.toString();
                isr.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return contentString;
    }

    @Override
    public List<BookContentInfo> getBookCatalogList() {
        return currCatalogList;
    }

    @Override
    public boolean isPageFetching() {
        return false;
    }

    /** 预读线程 */
    class PageFetchThread extends Thread {
        boolean isNext;

        public PageFetchThread(boolean isNext) {
            this.isNext = isNext;
        }

        @Override
        public void run() {
            synchronized (BookContentLocalAppEPUBParser.this) {
                if (isNext) {
                    if (cur_chapterindex < currCatalogList.size() - 1) {
                        if (nextInfo == null) {
                            nextInfo = getInfo(null, cur_chapterindex + 1);
                        }
                    }
                } else {
                    if (cur_chapterindex > 0) {
                        if (prevInfo == null) {
                            prevInfo = getInfo(null, cur_chapterindex - 1);
                        }
                    }
                }
            }
        }
    }

    @Override
    public BookContentInfo getCurrInfo(Activity context) {
        return currInfo;
    }

    @Override
    public void loadPrevInfo(Activity context, final OnAfterLoadPage onAfterLoadPage,
            BookContentInfo params) {
        synchronized (BookContentLocalAppEPUBParser.this) {
            final BookContentInfo info = getCurrInfo(context);
            context.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    onAfterLoadPage.runOnUiThread(info);
                }
            });
        }

    }

    @Override
    public void loadNextInfo(Activity context, final OnAfterLoadPage onAfterLoadPage,
            BookContentInfo params) {

        synchronized (BookContentLocalAppEPUBParser.this) {
            final BookContentInfo info = getCurrInfo(context);
            context.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    onAfterLoadPage.runOnUiThread(info);
                }
            });
        }

    }

    @Override
    public boolean hasPreChapter(int index) {
        cur_chapterindex--;
        Log4an.e("www", "【epub】pre cur_chapterindex=" + cur_chapterindex);
        return cur_chapterindex >= 0;
    }

    @Override
    public boolean hasNextChapter(int index) {
        cur_chapterindex++;
        Log4an.e("www", "【Epub】next cur_chapterindex=" + cur_chapterindex + ",lenth="
                + (currCatalogList.size() - 1));
        return cur_chapterindex <= currCatalogList.size() - 1;
    }

    /** 获取书籍和目录信息 */
    class EpubBookListHandler extends DefaultHandler {

        private BookContentInfo info;
        private boolean isText;
        private int which = -1;
        private final int DOCTITLE = 0;
        private final int DOCAUTHOR = 1;
        private final int NAVLABEL = 2;
        private final int OTHER = -1;
        private BookContentInfo currBookInfos;
        private int mPosition = 0;
        private boolean flag;

        public EpubBookListHandler(BookContentInfo currBookInfos) {
            this.currBookInfos = currBookInfos;

        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            if (isText) {
                String s = new String(ch, start, length);
                switch (which) {
                    case DOCTITLE:
                        if (currBookInfos != null) {
                            currBookInfos.setBookname(currBookInfos.getBookname() == null ? s
                                    : (currBookInfos.getBookname()));
                        }
                        break;
                    case DOCAUTHOR:
                        if (currBookInfos != null) {
                            currBookInfos.setAuthor(currBookInfos.getAuthor() == null ? s
                                    : (currBookInfos.getAuthor() + s));
                        }
                        break;
                    case NAVLABEL:
                        info.setCurChapterName(info.getCurChapterName() == null ? s : (info
                                .getCurChapterName() + s));
                        break;
                }
            }
        }

        @Override
        public void endElement(String uri, String localName, String name) throws SAXException {
            isText = false;
        }

        @Override
        public void startElement(String uri, String localName, String qName,
                org.xml.sax.Attributes attributes) throws SAXException {
            if ("docTitle".equals(localName)) {
                isText = false;
                which = DOCTITLE;

                try {
                    flag = false;
                    if (reference != null && reference.size() > 0) {
                        Log4an.i("youyang", "+++++" + reference.get(1).getCompleteHref());
                        for (char ch : reference.get(1).getCompleteHref().toCharArray()) {
                            if (isUnsafe(ch)) {
                                flag = true;
                                break;
                            } else {
                                flag = false;
                            }
                        }
                    }
                } catch (Exception e) {
                }

                // TODO
                if (reference.size() * 2 < spineList.size() || flag) {
                    Log4an.i("youyang", "reference.size():" + reference.size() + "====="
                            + "spineList.size():" + spineList.size());
                    if (list != null && list.size() > 0) {
                        list = new ArrayList<BookContentInfo>();
                    }
                    String href;
                    for (int i = 0, j = 1, q = 2; i < spineList.size(); i++) {
                        SpineReference spineReference = spineList.get(i);
                        info = new BookContentInfo();
                        String xhref = spineReference.getResource().getHref();
                        Log4an.i("youyang", spineReference.getResource().getTitle());
                        //每一章目录 对应好几个文件的情况
                        if (!flag) {
                            if (j <= reference.size()) {
                                if(reference.size()==1){
                                    href=reference.get(0).getCompleteHref();
                                }else{
                                    if(j<=reference.size()-1){
                                        href = reference.get(j).getCompleteHref();
                                    }else{
                                        href = reference.get(j-1).getCompleteHref(); 
                                    }
                                    
                                }
                                
                                if (xhref.equals(href)) {
                                    // info.setCurChapterName("第"+(j+1)+"章 "+reference.get(j).getTitle()+"("+1+")");
                                    if(reference.size()==1){
                                        info.setCurChapterName(reference.get(j-1).getTitle() + "(" + 1
                                                + ")"); 
                                    }else{
                                    info.setCurChapterName(reference.get(j).getTitle() + "(" + 1
                                            + ")");
                                    }
                                    j++;
                                    q = 2;
                                }else {
                                    if (i == 0) {
                                        // info.setCurChapterName("第1章 "+reference.get(j-1).getTitle());
                                        info.setCurChapterName(reference.get(j - 1).getTitle());
                                    } else {
                                        // info.setCurChapterName("第"+(j)+"章 "+reference.get(j-1).getTitle()+"("+q+")");
                                        info.setCurChapterName(reference.get(j - 1).getTitle() + "("
                                                + q + ")");
                                        q++;
                                    }
                                }
                            } 
                        } else {
                            //一个目录对应一个文件，但目录对应的src中含有非法字符
                            if (reference.size() >= spineList.size()) {
                                info.setCurChapterName(reference.get(i).getTitle());
                            } else {
                                info.setCurChapterName("第" + (i + 1) + "章");
                            }
                        }

                        info.setCurChapterCid(String.valueOf(i));
                        info.setChapterpath(Util.isNull(spineReference.getResource().getHref()));
                        list.add(info);
                    }
                }

            } else if ("docAuthor".equals(localName)) {
                isText = false;
                which = DOCAUTHOR;
            } else if ("navLabel".equals(localName)) {
                isText = false;
                which = NAVLABEL;
                if (reference.size() * 2 >= spineList.size() && !flag) {
                    info = new BookContentInfo();
                    info.setCurChapterCid(String.valueOf(mPosition++));
                    list.add(info);
                }
            } else if ("text".equals(localName)) {
                isText = true;
            } else if ("content".equals(localName)) {
                isText = false;
                // TODO 原有的代码
                if (reference.size() * 2 >= spineList.size() && !flag) {
                    info.setChapterpath(Util.isNull(attributes.getValue("src")));
                }
            } else {
                which = OTHER;
                isText = false;
            }

            super.startElement(uri, localName, qName, attributes);
        }

        public List<BookContentInfo> getParserData() {
            return list;
        }
    }

    /** youyang ----------------epub解析优化------------------- */
    /**
     * This is slightly unsafe: it lets / and % pass, making multiple encodes safe.
     * 
     * @param ch
     * @return
     */
    private static boolean isUnsafe(char ch) {
        if (ch > 128 || ch < 0)
            return true;
        return " %$&+,:;=?@<>#[]".indexOf(ch) >= 0;
    }

    private static String encode(String input) {
        StringBuilder resultStr = new StringBuilder();
        for (char ch : input.toCharArray()) {
            if (isUnsafe(ch)) {
                resultStr.append('%');
                resultStr.append(toHex(ch / 16));
                resultStr.append(toHex(ch % 16));
            } else {
                resultStr.append(ch);
            }
        }
        return resultStr.toString();
    }

    /**
     * 数字转化字符
     * 
     * @param ch
     * @return
     */
    private static char toHex(int ch) {
        return (char) (ch < 10 ? '0' + ch : 'A' + ch - 10);
    }

    /**
     * 将ncx中的href格式化（剔除特殊字符）
     * 
     * @param href
     * @param against
     * @return
     */
    private static String resolveHref(String href, String against) {
        try {
            String result = new URI(encode(against)).resolve(encode(href)).getPath();
            return result;
        } catch (URISyntaxException u) {
            return href;
        }
    }



    /** youyang ------------------epub解析优化------------------ */
}
